<?php
// +----------------------------------------------------------------------
// | Name: 咪乐多管理系统 [ 为了快速搭建软件应用而生的，希望能够帮助到大家提高开发效率。 ]
// +----------------------------------------------------------------------
// | Copyright: (c) 2020~2021 https://www.lvacms.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed: 这是一个自由软件，允许对程序代码进行修改，但希望您留下原有的注释。
// +----------------------------------------------------------------------
// | Author: 西安咪乐多软件 <997786358@qq.com>
// +----------------------------------------------------------------------
// | Version: V1
// +----------------------------------------------------------------------

/**
 * @Name  服务基类
 * @Description
 * @Auther 西安咪乐多软件
 * @Date 2021/6/11 12:30
 */

namespace Modules\Common\Services;


use Modules\Admin\Models\AdminImage;
use Modules\Admin\Services\Auth\TokenServices;
use Modules\Admin\Services\Config\ConfigServices;
use Modules\Common\Exceptions\ApiException;
use Modules\Common\Exceptions\CodeData;
use Modules\Common\Exceptions\MessageData;
use Modules\Common\Exceptions\StatusData;
use Illuminate\Support\Facades\Storage;
use Modules\Common\Lib\Oss\OssIndex;
use Modules\Common\Lib\Qiniu\QiniuIndex;

class BaseService
{
    public function __construct()
    {
    }

    /**
     * @name 查询条件
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/12 2:59
     * @param model Model 模型
     * @param params Array 查询参数
     * @param key String 模糊查询参数
     * @return Object
     **/
    function queryCondition(object $model,array $params,string $key="username"):Object
    {
        if (!empty($params['created_at'])){
            $model = $model->whereBetween('created_at',$params['created_at']);
        }
        if (!empty($params['updated_at'])){
            $model = $model->whereBetween('updated_at',$params['updated_at']);
        }
        if (!empty($params[$key])){
            $model = $model->where($key,'like','%' . $params[$key] . '%');
        }
        if (isset($params['status']) && $params['status'] != ''){
            $model = $model->where('status',$params['status']);
        }
        return $model;
    }
    /**
     * @name 搜索排序
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/12 2:59
     * @param model Model 模型
     * @param params Array 查询参数
     * @param key String 模糊查询参数
     * @return Object
     **/
    function querySort(object $model,string $sort):Object
    {
        $sort = json_decode($sort,true);
        $key = array_keys($sort)[0];
        $value = array_values($sort)[0];
        $model = $model->orderBy($key,$value);
        return $model;
    }
    /**
     * @name  成功返回
     * @description  用于所有的接口返回
     * @author 西安咪乐多软件
     * @date 2021/6/11 12:32
     * @param status Int 自定义状态码
     * @param message String 提示信息
     * @param data Array 返回信息
     * @return JSON
     **/
    public function apiSuccess(string $message = '',array $data = array(),int $status = StatusData::Ok){
        if($message == ''){
            $message = MessageData::Ok;
        }
        return response()->json([
            'status' => $status,
            'message'=> $message,
            'data'=>$data
        ],CodeData::OK);
    }

    /**
     * @name 失败返回
     * @description 用于所有的接口返回
     * @author 西安咪乐多软件
     * @date 2021/6/11 12:36
     * @param status Int 自定义状态码
     * @param message String 提示信息
     * @return JSON
     **/
    public function apiError(string $message = MessageData::API_ERROR_EXCEPTION,int $status = StatusData::BAD_REQUEST){
        throw new ApiException([
            'status' => $status,
            'message'=> $message
        ]);
    }
    /**
     * @name 添加公共方法
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/11 12:54
     * @param model Model  当前模型
     * @param data array 添加数据
     * @param successMessage string 成功返回数据
     * @param errorMessage string 失败返回数据
     * @return JSON
     **/
    public function commonCreate($model,array $data = [],string $successMessage = MessageData::ADD_API_SUCCESS,string $errorMessage = MessageData::ADD_API_ERROR){
        $data['created_at'] = date('Y-m-d H:i:s');
        if ($model->insert($data)){
            return $this->apiSuccess($successMessage);
        }
        $this->apiError($errorMessage);
    }
    /**
     * @name 编辑公共方法
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/11 13:17
     * @param model Model  当前模型
     * @param id   Int  修改id
     * @param data array 添加数据
     * @param successMessage string 成功返回数据
     * @param errorMessage string 失败返回数据
     * @return JSON
     **/
    public function commonUpdate($model,$id,array $data = [],string $successMessage = MessageData::UPDATE_API_SUCCESS,string $errorMessage = MessageData::UPDATE_API_ERROR){
        $data['updated_at'] = date('Y-m-d H:i:s');
        if ($model->where('id',$id)->update($data)){
            return $this->apiSuccess($successMessage);
        }
        $this->apiError($errorMessage);
    }
    /**
     * @name 调整公共方法
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/11 13:31
     * @param model Model  当前模型
     * @param id   Int  修改id
     * @param data array 添加数据
     * @param successMessage string 成功返回数据
     * @param errorMessage string 失败返回数据
     * @return JSON
     **/
    public function commonStatusUpdate($model,$id,array $data = [],string $successMessage = MessageData::STATUS_API_SUCCESS,string $errorMessage = MessageData::STATUS_API_ERROR){
        if ($model->where('id',$id)->update($data)){
            return $this->apiSuccess($successMessage);
        }
        $this->apiError($errorMessage);
    }
    /**
     * @name 排序公共方法
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/11 13:31
     * @param model Model  当前模型
     * @param id   Int  修改id
     * @param data array 添加数据
     * @param successMessage string 成功返回数据
     * @param errorMessage string 失败返回数据
     * @return JSON
     **/
    public function commonSortsUpdate($model,$id,array $data = [],string $successMessage = MessageData::STATUS_API_SUCCESS,string $errorMessage = MessageData::STATUS_API_ERROR){
        if ($model->where('id',$id)->update($data) !== false){
            return $this->apiSuccess($successMessage);
        }
        $this->apiError($errorMessage);
    }
    /**
     * @name 真删除公共方法
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/11 13:33
     * @param model Model  当前模型
     * @param ArrId Array  删除id
     * @param successMessage string 成功返回数据
     * @param errorMessage string 失败返回数据
     * @return JSON
     **/
    public function commonDestroy($model,array $ArrId,string $successMessage = MessageData::DELETE_API_SUCCESS,string $errorMessage = MessageData::DELETE_API_ERROR){
        if ($model->whereIn('id',$ArrId)->delete()){
            return $this->apiSuccess($successMessage);
        }
        $this->apiError($errorMessage);
    }
    /**
     * @name 假删除公共方法
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/11 13:35
     * @param model Model  当前模型
     * @param idArr Array  删除id
     * @param successMessage string 成功返回数据
     * @param errorMessage string 失败返回数据
     * @return JSON
     **/
    public function commonIsDelete($model,array $idArr,string $successMessage = MessageData::DELETE_API_SUCCESS,string $errorMessage = MessageData::DELETE_API_ERROR){
        if ($model->whereIn('id',$idArr)->update(['is_delete'=>1,'deleted_at'=>date('Y-m-d H:i:s')])){
            return $this->apiSuccess($successMessage);
        }
        $this->apiError($errorMessage);
    }
    /**
     * @name 假删除恢复公共方法
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/11 13:35
     * @param model Model  当前模型
     * @param idArr Array  删除id
     * @param successMessage string 成功返回数据
     * @param errorMessage string 失败返回数据
     * @return JSON
     **/
    public function commonRecycleIsDelete($model,array $idArr,string $successMessage = MessageData::DELETE_RECYCLE_API_SUCCESS,string $errorMessage = MessageData::DELETE_RECYCLE_API_ERROR){
        if ($model->whereIn('id',$idArr)->update(['is_delete'=>0])){
            return $this->apiSuccess($successMessage);
        }
        $this->apiError($errorMessage);
    }

    /**
     * @param int $open
     * @param bool $status
     * @return String
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/12 0:25
     */
    public static function getHttp(int $open = 1,bool $status = false):String
    {
        if($open == 1){
            if(isset($_SERVER['HTTP_HOST'])){
                $http = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
                return $http.$_SERVER['HTTP_HOST'];
            }else{
                return "";
            }
        }else if($open == 2){
            $http = config('filesystems.disks.qiniu.domains.https')?'https://' : 'http://';
            return $http . (config('filesystems.disks.qiniu.domains.default')?:config('filesystems.disks.qiniu.domains.https'));
        }else if($open == 3){
            $http = config('filesystems.disks.oss.ssl')?'https://' : 'http://';
            if($status || config('filesystems.disks.oss.cname_bucket') == ''){
                return $http.config('filesystems.disks.oss.bucket').'.'.config('filesystems.disks.oss.endpoint');
            }else{
                return $http.config('filesystems.disks.oss.cname_bucket');
            }
        }
    }
    /**
     * @name 将编辑器的content的图片转换为相对路径
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/12 0:28
     * @param content String 内容
     * @return string
     **/
    public function setPicUrl(string $content = ''):String
    {
        if ($content){
            //提取图片路径的src的正则表达式 并把结果存入$matches中
            preg_match_all("/<[img|IMG].*?src=[\'|\"](.*?)[\'|\"].*?[\/]?>/",$content,$matches);
            $img = "";
            if(!empty($matches)) {
                //注意，上面的正则表达式说明src的值是放在数组的第三个中
                $img = $matches[1];
            }else {
                $img = "";
            }

            if (!empty($img)) {
                $patterns = array();
                $replacements = array();
                foreach($img as $imgItem){
                    $replacements[] = self::setFinalImgUrl($imgItem,true);
                    $patterns[] = $imgItem;
                }
                //让数组按照key来排序
                ksort($patterns);
                ksort($replacements);
                //替换内容
                foreach ($replacements as $k=>$v){
                    $content = str_replace($patterns[$k],$v,$content);
                }
            }
        }
        return $content;
    }



    public function setPicUrlContent(string $content = ''):String
    {
        if ($content){
            //提取图片路径的src的正则表达式 并把结果存入$matches中
            preg_match_all("/<[img|IMG].*?src=[\'|\"](.*?)[\'|\"].*?[\/]?>/",$content,$matches);
            $img = "";
            if(!empty($matches)) {
                //注意，上面的正则表达式说明src的值是放在数组的第三个中
                $img = $matches[1];
            }else {
                $img = "";
            }
            if (!empty($img)) {
                $patterns= array();
                $replacements = array();
                foreach($img as $imgItem){
                    $replacements[] = self::setFinalImgUrl($imgItem);
                    $patterns[] = $imgItem;
                }
                //让数组按照key来排序
                ksort($patterns);
                ksort($replacements);
                foreach ($replacements as $k=>$v){
                    $content = str_replace($patterns[$k],$v,$content);
                }
            }
        }
        return $content;
    }

    private static function getFinalImgUrl(string $imgItem){
        $open = (int)(substr($imgItem,1,1));
        if(!in_array($open,[2,3])){
            $open = 1;
        }
        return self::getHttp($open).$imgItem;
    }

    private static function setFinalImgUrl(string $imgItem,bool $status=false):string
    {
        $httpUrl1 = self::getHttp(1);
        $httpUrl2 = self::getHttp(2);
        $httpUrl3 = self::getHttp(3);
        if($status === false){
            if (strpos($imgItem, $httpUrl1) !== false || strpos($imgItem, $httpUrl2) !== false || strpos($imgItem, $httpUrl3) !== false) {
                return $imgItem;
            }
        }else{
            if (strpos($imgItem, $httpUrl1) !== false){
                return str_replace($httpUrl1,"",$imgItem);
            }else if (strpos($imgItem, $httpUrl2) !== false){
                return str_replace($httpUrl2,"",$imgItem);
            }else if (strpos($imgItem, $httpUrl3) !== false){
                return str_replace($httpUrl3,"",$imgItem);
            }
        }
        return self::contentPicUpload($imgItem,$status);
    }
    private static function contentPicUpload(string $url,bool $status=false):string
    {
        $imageStatus = ConfigServices::getCodeValue('SiteConfiguration')['image_status'];
        $urlContent = file_get_contents($url);
        $imgUrl = '';
        if($imageStatus == 1){
            $srcName = self::getRandStr(20);
            $date = date('Ymd');
            $imgUrl = "/storage/upload/".$date."/".$srcName.".png";
            Storage::disk('public')->put($date.'/'.$srcName.'.png', $urlContent);
        }else if($imageStatus == 2){
            $imgUrl = QiniuIndex::contentUpload($urlContent,$url);
        }else if($imageStatus == 3){
            $imgUrl = OssIndex::contentUpload($urlContent,$url);
        }
        if ($imgUrl) {
             $userInfo = TokenServices::my();
             AdminImage::insertGetId([
                'url' => $imgUrl,
                'open' => $imageStatus,
                'admin_id' => $userInfo->id,
                'status' => 0,
                'created_at' => date('Y-m-d H:i:s')
             ]);
        }
        if($status){
            return $imgUrl;
        }
        return self::getHttp($imageStatus) .$imgUrl;
    }


    /**
     * @name 将编辑器的content的图片转换为绝对路径
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/12 0:33
     * @param  content string 内容
     * @return String
     **/
    public function getReplacePicUrl(string $content = ''):String
    {
        if ($content){
            //提取图片路径的src的正则表达式 并把结果存入$matches中
            preg_match_all("/<[img|IMG].*?src=[\'|\"](.*?(?:[\.gif|\.jpg|\.png]))[\'|\"].*?[\/]?>/",$content,$matches);
            $img = "";
            if(!empty($matches)) {
                //注意，上面的正则表达式说明src的值是放在数组的第三个中
                $img = $matches[1];
            }else {
                $img = "";
            }
            if (!empty($img)) {
                $patterns= array();
                $replacements = array();
                foreach($img as $imgItem){
                    $replacements[] = self::getFinalImgUrl($imgItem);
                    $img_new = "/".preg_replace("/\//i","\/",$imgItem)."/";
                    $patterns[] = $img_new;
                }
                //让数组按照key来排序
                ksort($patterns);
                ksort($replacements);
                //替换内容
                $content = preg_replace($patterns, $replacements, $content);
            }
        }
        return $content;
    }
    /**
     * @name 生成随机字符串
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/12 0:38
     * @param length Int 生成字符串长度
     * @return String
     **/
    public static function getRandStr(int $length = 11):String
    {
        //字符组合
        $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $len = strlen($str)-1;
        $randstr = '';
        for ($i=0;$i<$length;$i++) {
            $num=mt_rand(0,$len);
            $randstr .= $str[$num];
        }
        return $randstr;
    }
    /**
     * @name  处理二维数组转为json字符串乱码问题
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/12 0:40
     * @param data Array  需要转为json字符串的数组
     * @return String
     **/
    public function setJsonEncodes($data):String
    {
        $count = count($data);
        for($k=0;$k<$count;$k++){
            foreach($data[$k] as $key => $value){
                $data[$k][$key] = urlencode($value);
            }
        }
        return urldecode(json_encode($data));
    }

    /**
     * @name 传入时间戳,计算距离现在的时间
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/12 2:55
     * @param theTime Int 时间戳
     * @return String
     **/
    public function formatTime(int $theTime = 0):String
    {
        $nowTime = time();
        $dur = $nowTime - $theTime;
        if ($dur < 0) {
            return $theTime;
        } else {
            if ($dur < 60) {
                return $dur . '秒前';
            } else {
                if ($dur < 3600) {
                    return floor($dur / 60) . '分钟前';
                } else {
                    if ($dur < 86400) {
                        return floor($dur / 3600) . '小时前';
                    } else {//昨天
                        //获取今天凌晨的时间戳
                        $day = strtotime(date('Y-m-d', time()));
                        //获取昨天凌晨的时间戳
                        $pday = strtotime(date('Y-m-d', strtotime('-1 day')));
                        if ($theTime > $pday && $theTime < $day) {//是否昨天
                            return $t = '昨天 ' . date('H:i', $theTime);
                        } else {
                            if ($dur < 172800) {
                                return floor($dur / 86400) . '天前';
                            } else {
                                return date('Y-m-d H:i', $theTime);
                            }
                        }
                    }
                }
            }
        }
    }
    /**
     * @name 处理递归数据
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/12 1:23
     * @param array Array  总数据
     * @param pid Int  父级id
     * @return Array
     **/
    public function tree(array $array,int $pid=0):Array
    {
        $tree = array();
        foreach ($array as $key => $value) {
            if ($value['pid'] == $pid) {
				$value['value'] = $value['id'];
				$value['key'] = strval($value['id']);
				$value['title'] = $value['name'];
                $value['children'] = $this->tree($array, $value['id']);
                if (!$value['children']) {
                    unset($value['children']);
                }
                $tree[] = $value;
            }
        }
        return $tree;
    }
    /**
     * @name PHP格式化字节大小
     * @description
     * @author 西安咪乐多软件
     * @date 2021/6/23 17:02
     * @param size Int  字节数
     * @param delimiter string  数字和单位分隔符
     * @return String 格式化后的带单位的大小
     **/
    public static function formatBytes(int $size,string $delimiter = ''):String
    {
        $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
        for ($i = 0; $size >= 1024 && $i < 5; $i++) $size /= 1024;
        return round($size, 2) . $delimiter . $units[$i];
    }
    /**
     * 获取客户端IP地址
     * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
     * @param boolean $adv 是否进行高级模式获取（有可能被伪装）
     * @return mixed
     */
    public static function getClientIp($type = 0, $adv = false) {
        $type = $type ? 1 : 0;
        static $ip = NULL;
        if ($ip !== NULL)
            return $ip[$type];
        if ($adv) {
            if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
                $pos = array_search('unknown', $arr);
                if (false !== $pos)
                    unset($arr[$pos]);
                $ip = trim($arr[0]);
            }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
                $ip = $_SERVER['HTTP_CLIENT_IP'];
            } elseif (isset($_SERVER['REMOTE_ADDR'])) {
                $ip = $_SERVER['REMOTE_ADDR'];
            }
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        // IP地址合法验证
        $long = sprintf("%u", ip2long($ip));
        $ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
        return $ip[$type];
    }
    //
    public static function unSerialize(string $serial_str):Array
    {
        $serial_str = preg_replace_callback('#s:(\d+):"(.*?)";#s',function($match){
            return 's:'.strlen($match[2]).':"'.$match[2].'";';
        },$serial_str);
        $serial_str = str_replace("\r", "", $serial_str);
        return unserialize($serial_str);
    }
    // 获取文件后缀
    public function getSuffix($url){
        $pos = strpos($url,'.',1);
        return substr($url,$pos+1);
    }
}
